/*
	Copyright (C) 2011 Salil Bhagurkar

	This file is part of illusion

	illusion is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	illusion is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with illusion.
	If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * Application to perform user mode tests on the syscalls / apimod of illusion
 */

#include <apimod/apimod.h>
#include <kernel/types.h>
#include <kernel/ilapp_base.h>
#include <kernel/vfs.h>
#include <kernel/errors.h>

static struct apimod_console *con;
static struct apimod_string *stringy;
static struct apimod_base *base;
static struct apimod_lib_string *lib_string;
static struct apimod_fs *fs;
static struct apimod_fs1 *fs1;
static struct apimod_lib_memory *m;

static uint_t total_count = 0, pass_count = 0;


static int __test_assert(char *desc, int result)
{
	total_count++;
	if(result)
	{
		con->printf("Pass: test(%s)\n", desc);
		pass_count++;
		return true;
	}
	else
	{
		con->printf("Fail: test(%s)\n", desc);
		return false;
	}
}

#define test_assert(name, condition) if(!(__test_assert(name, condition))) return 0

static int string_test()
{
	string my_string;
	stringy->init(&my_string);
	test_assert("String test1", my_string.value != null);
	stringy->append(&my_string, "stuff");
	test_assert("String test2", my_string.length == 5);
	test_assert("String test3", my_string.value[my_string.length - 1] == '\0');
	return true;
}

static int base_test()
{
	uint_t fid;
	base->get_current(&fid);
	fs->close(fid);
	void *pages = base->get_pages(10);
	test_assert("Base test1", pages != null);
	base->free_pages(pages, 10);
	uint_t build_number = 0, build_date = 0;
	base->get_version(&build_number, &build_date);
	test_assert("Base test2", build_number > 0);
	uint_t pid;
	base->create_process(&pid, "illusion:/rdisk/umtest.exe", "");
	test_assert("Base test3", pid > 0);
	base->resume_process(pid);
	base->pause_process(pid);
	base->resume_process(pid);
	base->wait_for_process(pid);
	base->kill_process(pid);
	base->create_process(&pid, "illusion:/rdisk/umtest.exe", "");
	fs1->create_file(".", "temp.txt");
	fs->open("temp.txt", STATE_WRITE, &fid);
	base->redirect_out(pid, fid);
	base->resume_process(pid);
	base->wait_for_process(pid);
	base->kill_process(pid);
	fs->close(fid);
	uint_t len;
	char *data = fs1->read_all_file(&len, "temp.txt");
	test_assert("Base test4", m->equals(data, "umtest\n", 7));
	m->free(data, len);
	fs1->delete_file("temp.txt");
	base->try();
	int err = fs->open("temp.txt", STATE_READ, &fid);
	base->exit_try();
	test_assert("Base test5", err == ENOENT);
	return true;
}


static int (*test_method[])() = {base_test, string_test};

int ilapp_main()
{
	GETI("base", &base);
	GETI("console", &con);
	GETI("string", &stringy);
	GETI("lib_string", &lib_string);
	GETI("fs", &fs);
	GETI("fs1", &fs1);
	GETI("memory", &m);

	uint_t length;
	char *args = base->get_arguments(&length);

	uint_t nr_tests = sizeof(test_method) / sizeof(*test_method);

	if(args != null && lib_string->equals(args, "all")) {

		for(uint_t i = 0; i < nr_tests; i++)
		{
			test_method[i]();
		}

		con->printf("umtest: Success = %d / %d (%u%%)\n", pass_count, total_count, (pass_count * 100) / total_count);
	} else {
		con->printf("umtest\n");
	}

	return 0;
}

